
object HigherOrderFunctionsDemo extends App {
  case class Student(
                      name: String,
                      className: String,
                      grade: Int,
                      gender: String,
                      age: Int,
                      scores: Map[String, Double]
                    )

  val students = List(
    Student("张三", "大数据2301", 2023, "男", 19, Map("数学" -> 95.0, "语文" -> 88.0)),
    Student("李四", "大数据2301", 2023, "女", 18, Map("数学" -> 89.0, "语文" -> 76.0)),
    Student("王五", "大数据2302", 2023, "男", 19, Map("数学" -> 85.0, "语文" -> 92.0)),
    Student("赵六", "大数据2302", 2023, "女", 18, Map("数学" -> 72.0, "语文" -> 68.0)),
    Student("钱七", "人工智能2301", 2023, "男", 20, Map("数学" -> 92.0, "语文" -> 85.0)),
    Student("孙八", "人工智能2301", 2023, "女", 19, Map("数学" -> 88.0, "语文" -> 90.0))
  )

  val groupByClass = (s: Student) => s.className
  val groupByGender = (s: Student) => s.gender
  val groupByGrade = (s: Student) => s.grade

  def groupAndAggregate[T, R](
                               data: List[Student],
                               groupFunc: Student => T,
                               aggFunc: List[Student] => R
                             ): Map[T, R] = {
    data.groupBy(groupFunc).map { case (key, group) =>
      (key, aggFunc(group))
    }
  }

  val countStudents = (group: List[Student]) => group.size
  val averageAge = (group: List[Student]) => group.map(_.age).sum.toDouble / group.size
  val averageMathScore = (group: List[Student]) => {
    val total = group.flatMap(_.scores.get("数学")).sum
    total / group.size
  }

  println("===按班级统计学生数量===")
  val classCount = groupAndAggregate(students, groupByClass, countStudents)
  classCount.foreach { case (className, count) =>
    println(s"$className: $count 人")
  }
  println("\n=== 按性别统计平均年龄==")
  val genderAgeAvg = groupAndAggregate(students, groupByGender, averageAge)
  genderAgeAvg.foreach { case (gender, avg) =>
    println(f"$gender: $avg%.1f 岁")
  }
  println("\n=== 按班级统计数学平均分===")
  val classMathAvg = groupAndAggregate(students, groupByClass, averageMathScore)
  classMathAvg.foreach { case (className, avg) =>
    println(f"$className: $avg%.1f 分")
  }

  def createSubjectAvgFunc(subject: String): List[Student] => Double = {
    (group: List[Student]) => {
      val total = group.flatMap(_.scores.get(subject)).sum
      if (group.isEmpty) 0.0 else total / group.size
    }
  }

  val chineseAvgFunc = createSubjectAvgFunc("语文")
  println("\n=== 按年级统计语文平均分==")
  val gradeChineseAvg = groupAndAggregate(students, groupByGrade, chineseAvgFunc)
  gradeChineseAvg.foreach { case (grade, avg) =>
    println(f"$grade 年级: $avg%.1f 分")
  }
}